`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company: 
// Engineer: 
// 
// Create Date: 2021/03/30 09:11:20
// Design Name: 
// Module Name: axi_master_read
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//////////////////////////////////////////////////////////////////////////////////


module axi_master_read#(
    parameter   axi_data_width          =   512         
    )(
    input   wire                m_axi_aclk      ,               
    input   wire                m_axi_reset     ,
        
    input   wire                start_read      ,
    input   wire    [31:0]      address         ,
    input   wire    [7:0]       burst_length    ,
    input   wire    [2:0]       burst_size      ,
    input   wire    [1:0]       increment_burst ,
    output  reg                 done            ,
    output  reg                 error           ,
    output  reg                 busy            ,
//  data output
    output  wire    [axi_data_width-1:0]        dout            ,
    output  wire                dout_valid      ,
    input   wire                dout_ready      ,
//  AXI4 Read Address Channel   
    input   wire                m_axi_arready   ,               
    output  reg                 m_axi_arvalid   ,           
    output  reg     [31:0]      m_axi_araddr    ,           
    output  wire    [3:0]       m_axi_arid      ,           
    output  reg     [7:0]       m_axi_arlen     ,           
    output  reg     [2:0]       m_axi_arsize    ,           
    output  reg     [1:0]       m_axi_arburst   ,           
    output  wire                m_axi_arlock    ,        
    output  wire    [3:0]       m_axi_arcache   ,           
    output  wire    [2:0]       m_axi_arprot    ,           
    output  wire    [3:0]       m_axi_arqos     ,           
    output  wire    [3:0]       m_axi_arregion  ,           
//  outAXI4 Read Data Channel
    output  wire                m_axi_rready    ,          
    input   wire                m_axi_rvalid    ,       
    input   wire    [axi_data_width-1:0]        m_axi_rdata     ,       
    input   wire    [1:0]       m_axi_rresp     ,       
    input   wire    [3:0]       m_axi_rid       ,       
    input   wire                m_axi_rlast     
    );
    
    localparam  IDLE        =   'd0,
                WR_ADDR     =   'd1,
                WT_DATA     =   'd2,
                COMPELTE    =   'd3,
                ERROR       =   'd4;    
    
    assign  m_axi_arid      =   'd0;                

    assign  m_axi_arlock    =   'd0;
    assign  m_axi_arcache   =   'd0;
    assign  m_axi_arprot    =   'd0;
    assign  m_axi_arqos     =   'd0;
    assign  m_axi_arregion  =   'd0;
    assign  m_axi_rready     = dout_ready;
    
    always @(posedge m_axi_aclk)
        if(m_axi_reset) begin
            m_axi_araddr    <=  'd0;
            m_axi_arlen     <=  'd0;
            m_axi_arsize    <=  'd0;
            m_axi_arburst   <=  'd0;
        end
        else if(start_read)begin
            m_axi_araddr    <=  address;
            m_axi_arlen     <=  burst_length;
            m_axi_arsize    <=  burst_size;
            m_axi_arburst   <=  increment_burst;
        end  
        
    reg     [2:0]   state,nx_state; 
    always @(posedge m_axi_aclk)
        if(m_axi_reset)
            state <= IDLE;
        else 
            state <= nx_state;
    
    always @(*)
        case(state)
            IDLE        :   if(start_read) nx_state = WR_ADDR; else nx_state = IDLE;    
            WR_ADDR     :   if(m_axi_arvalid & m_axi_arready)nx_state = WT_DATA; else nx_state = WR_ADDR;
            WT_DATA     :   begin   
                                if(m_axi_rlast & m_axi_rready & m_axi_rvalid) begin
                                    if(m_axi_rresp == 2'b00)    
                                        nx_state = COMPELTE; 
                                    else
                                        nx_state = ERROR; 
                                    end
                                else 
                                    nx_state = WT_DATA;             
                            end
            COMPELTE    :   nx_state = IDLE;
            ERROR       :   nx_state = IDLE;
            default     :   nx_state = IDLE;
        endcase 
    
    always @(posedge m_axi_aclk)
        case(state)
            WR_ADDR     :   if(m_axi_arvalid & m_axi_arready )m_axi_arvalid   <=  1'd0;else m_axi_arvalid   <=  1'd1;
            default     :   m_axi_arvalid   <=  1'd0;
        endcase 
    
    always @(posedge m_axi_aclk)
        case(state)
            ERROR       :   error   <= 1'd1;
            default     :   error   <= 1'd0;
        endcase
        
    always @(posedge m_axi_aclk)
        case(state)
            COMPELTE    :   done <= 1'd1;
            default     :   done    <= 1'd0;
        endcase 
        
    always @(posedge m_axi_aclk)
        case(state)
            IDLE    :   busy    <=  1'd0;
            default :   busy    <=  1'd1;
        endcase 
    
    assign  dout        =   m_axi_rdata;    
    assign  dout_valid  =   m_axi_rvalid & m_axi_rready;
    
    
endmodule
